﻿
using MicroDb.Mysql;

using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

using MySqlConnector;

using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Linq.Expressions;

using Utils;

namespace MicroDb.Querys
{
    public class DBQueryProvider : IQueryProvider
    {
        private readonly MicroDbType microDbType;

        public SqlExecute SqlExecute { get; }
        public IMemoryCache MemoryCache { get; }

        /// <summary>
        /// 获取多个执行器
        /// </summary>
        /// <param name="dbSources"></param>
        /// <returns></returns>
        public SqlExecute[] AppendSqlExecutes(params IQueryable[] queryables)
        {
            List<SqlExecute> sqlExecutes = new List<SqlExecute>();
            // 自己的执行器
            sqlExecutes.Add(SqlExecute);

            for (int i = 0; i < queryables.Length; i++)
            {
                var provider = queryables[i].Provider as DBQueryProvider;
                if (sqlExecutes.Contains(provider.SqlExecute))
                    continue;
                sqlExecutes.Add(provider.SqlExecute);
            }
            return sqlExecutes.ToArray();
        }
        public DBQueryProvider(IServiceProvider serviceProvider, IOptions<MicroDbOptions> dbOptions, string dbSource, IMemoryCache memoryCache = null)
        {
            if (!dbOptions.Value.DbConnectionBuilders.TryGetValue(dbSource, out (MicroDbType microDbType, string connectionString) value))
            {
                throw new ArgumentNullException("数据源：" + dbSource + "不存在");
            }
            this.microDbType = value.microDbType;
            this.MemoryCache = memoryCache;
            this.SqlExecute = DBQueryProviderFactory.GetSqlExecute(serviceProvider, dbSource, value.connectionString, microDbType);
        }


        public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
        {
            if (expression == null) return new DBQueryable<TElement>(this);
            return new DBQueryable<TElement>(expression, this);
        }

        public IQueryable CreateQuery(Expression expression)
        {
            throw new NotImplementedException();
        }

        public object Execute(Expression expression)
        {
            switch (microDbType)
            {
                case MicroDbType.MySql:
                    return MysqlResolveBase.CreateResolve(expression, sqlExecute: SqlExecute).GetResult();
                case MicroDbType.SqlServer:
                    break;
                case MicroDbType.Oracle:
                    break;
                default:
                    break;
            }
            return null;
        }


        public TResult Execute<TResult>(Expression expression)
        {
            object obj = Execute(expression);
            if (obj is TResult t)
            {
                return t;
            }
            return (TResult)Convert.ChangeType(obj, typeof(TResult));
        }


    }
}
